<?php

namespace DocBoot\Annotation;

use DocBoot\Controller\ControllerContainer;
use DocBoot\Entity\EntityContainer;

abstract class ContainerBuilder
{
    /**
     * ContainerBuilder constructor.
     * @param array $annotations 需加载的注释和顺序
     * 语法 http://jmespath.org/tutorial.html
     *
     *  [
     *      [PropertyAnnotationHandler::class,   'property'],
     *      ...
     *  ];
     *
     */
    public function __construct(array $annotations)
    {
        $this->annotations = $annotations;
    }

    /**
     * load from class with local cache
     * @param string $className
     * @return ControllerContainer|EntityContainer
     */
    public function build(string $className): EntityContainer|ControllerContainer
    {
        return $this->buildWithoutCache($className);

        //TODO【重要】 使用全局的缓存版本号, 而不是针对每个文件判断缓存过期与否
//        $rfl = new \ReflectionClass($className) or \DocBoot\abort("load class $className failed");
//        $fileName = $rfl->getFileName();
//        $key = str_replace('\\','.',get_class($this)).md5(serialize($this->annotations).$fileName.$className);
//        $cache = new CheckableCache($this->cache);
//        $res = $cache->get($key, $this);
//        if($res === $this){
//            try{
//                $meta = $this->buildWithoutCache($className);
//                $cache->set($key, $meta, 0, $fileName?new ClassModifiedChecker($className):null);
//                return $meta;
//            }catch (\Exception $e){
//                Logger::warning(__METHOD__.' failed with '.$e->getMessage());
//                $cache->set($key, $e->getMessage(), 0, $fileName?new ClassModifiedChecker($className):null);
//                throw $e;
//            }
//        }elseif(is_string($res)){
//            \DocBoot\abort($res);
//        }else{
//            return $res;
//        }
    }

    /**
     * @param string $className
     */
    abstract protected function createContainer($className);

    protected function handleAnnotation($handlerName, $container, $ann)
    {
        $handler = $container->make($handlerName);
        return $handler($container, $ann);
    }
    /**
     * @param $className
     * @return ControllerContainer|EntityContainer
     */
    public function buildWithoutCache($className): EntityContainer|ControllerContainer
    {
        $container = $this->createContainer($className);
        $anns = AnnotationReader::read($className);
        foreach ($this->annotations as $i){
            list($class, $target) = $i;

            $found = \JmesPath\search($target, $anns);
            if (empty($found)) {
                continue;
            }
            if(is_array($found)){
                foreach ($found as $f){
                    $this->handleAnnotation($class, $container,$f); //TODO 支持
                }
            } else {
                $this->handleAnnotation($class, $container, $found);
            }
        }
        return $container;
    }

    /**
     * @var array
     */
    private $annotations=[];
}